---
title: Styling
description: Learn how to customize the appearance of Streamdown components.
---

Streamdown is designed to be flexible and customizable, allowing you to adapt its appearance to match your application's design system. This guide covers the various ways you can modify Streamdown's styles to suit your needs.

## CSS Variables (Recommended)

Streamdown components are built using shadcn/ui's design system, which means they use CSS variables for theming. This is the simplest way to customize colors, borders, and other design tokens across all Streamdown components.

### Setting Up Variables

Add or modify the CSS variables in your `globals.css` file:

```css title="app/globals.css"
@layer base {
  :root {
    --background: 0 0% 100%;
    --foreground: 222.2 84% 4.9%;
    --card: 0 0% 100%;
    --card-foreground: 222.2 84% 4.9%;
    --popover: 0 0% 100%;
    --popover-foreground: 222.2 84% 4.9%;
    --primary: 222.2 47.4% 11.2%;
    --primary-foreground: 210 40% 98%;
    --secondary: 210 40% 96.1%;
    --secondary-foreground: 222.2 47.4% 11.2%;
    --muted: 210 40% 96.1%;
    --muted-foreground: 215.4 16.3% 46.9%;
    --accent: 210 40% 96.1%;
    --accent-foreground: 222.2 47.4% 11.2%;
    --destructive: 0 84.2% 60.2%;
    --destructive-foreground: 210 40% 98%;
    --border: 214.3 31.8% 91.4%;
    --input: 214.3 31.8% 91.4%;
    --ring: 222.2 84% 4.9%;
    --radius: 0.5rem;
  }

  .dark {
    --background: 222.2 84% 4.9%;
    --foreground: 210 40% 98%;
    --card: 222.2 84% 4.9%;
    --card-foreground: 210 40% 98%;
    --popover: 222.2 84% 4.9%;
    --popover-foreground: 210 40% 98%;
    --primary: 210 40% 98%;
    --primary-foreground: 222.2 47.4% 11.2%;
    --secondary: 217.2 32.6% 17.5%;
    --secondary-foreground: 210 40% 98%;
    --muted: 217.2 32.6% 17.5%;
    --muted-foreground: 215 20.2% 65.1%;
    --accent: 217.2 32.6% 17.5%;
    --accent-foreground: 210 40% 98%;
    --destructive: 0 62.8% 30.6%;
    --destructive-foreground: 210 40% 98%;
    --border: 217.2 32.6% 17.5%;
    --input: 217.2 32.6% 17.5%;
    --ring: 212.7 26.8% 83.9%;
  }
}
```

### Variables Used by Streamdown

Streamdown components primarily use these CSS variables:

| Variable | Usage | Example Elements |
|----------|-------|------------------|
| `--primary` | Links, accent colors | Links (`<a>`) |
| `--primary-foreground` | Text on primary backgrounds | N/A |
| `--muted` | Subtle backgrounds | Code blocks, table headers |
| `--muted-foreground` | De-emphasized text | Blockquote text |
| `--border` | Borders and dividers | Tables, horizontal rules, code blocks |
| `--ring` | Focus rings on interactive elements | Buttons (copy, download) |
| `--radius` | Border radius | Code blocks, tables, buttons |

### Quick Theme Examples

**Minimal Gray Theme:**

```css title="app/globals.css"
:root {
  --primary: 0 0% 20%;
  --muted: 0 0% 96%;
  --border: 0 0% 90%;
  --radius: 0.25rem;
}
```

**Vibrant Blue Theme:**

```css title="app/globals.css"
:root {
  --primary: 217 91% 60%;
  --muted: 214 100% 97%;
  --border: 214 32% 91%;
  --radius: 0.75rem;
}
```

**No Borders Theme:**

```css title="app/globals.css"
:root {
  --border: transparent;
  --muted: 0 0% 98%;
  --radius: 0rem;
}
```

## Custom Components

The most powerful way to customize Streamdown's appearance is by providing custom component overrides. This allows you to replace any Markdown element with your own React component while maintaining all of Streamdown's functionality.

### Basic Usage

Pass custom components using the `components` prop:

```tsx title="app/page.tsx"
<Streamdown
  components={{
    h1: ({ children }) => (
      <h1 className="text-4xl font-bold text-blue-600">
        {children}
      </h1>
    ),
    h2: ({ children }) => (
      <h2 className="text-3xl font-semibold text-blue-500">
        {children}
      </h2>
    ),
    p: ({ children }) => (
      <p className="text-gray-700 leading-relaxed">
        {children}
      </p>
    ),
  }}
>
  {markdown}
</Streamdown>
```

### Available Components

You can override any of the following components:

- **Headings**: `h1`, `h2`, `h3`, `h4`, `h5`, `h6`
- **Text**: `p`, `strong`, `em`
- **Lists**: `ul`, `ol`, `li`
- **Links**: `a`
- **Code**: `code`, `pre`
- **Quotes**: `blockquote`
- **Tables**: `table`, `thead`, `tbody`, `tr`, `th`, `td`
- **Media**: `img`
- **Other**: `hr`, `sup`, `sub`, `section`

### Component Props

Custom components receive all the props that the default components would receive, including:

- `children` - The content to render
- `className` - CSS class names (if applicable)
- `node` - The Markdown AST node (for advanced use cases)
- Element-specific props (e.g., `href` for links, `src` for images)

```tsx title="app/page.tsx"
<Streamdown
  components={{
    a: ({ href, children, ...props }) => (
      <a
        href={href}
        className="text-purple-600 hover:text-purple-800 underline"
        {...props}
      >
        {children} 🔗
      </a>
    ),
  }}
>
  {markdown}
</Streamdown>
```

## Global CSS Targeting

For simpler styling needs, you can use global CSS to target Streamdown elements using the `data-streamdown` attribute. Every Streamdown element includes a unique `data-streamdown` attribute that makes it easy to apply custom styles.

### Available Selectors

Target specific Streamdown elements using these data attributes:

```css title="styles/streamdown.css"
/* Headings */
[data-streamdown="heading-1"] { }
[data-streamdown="heading-2"] { }
[data-streamdown="heading-3"] { }
[data-streamdown="heading-4"] { }
[data-streamdown="heading-5"] { }
[data-streamdown="heading-6"] { }

/* Text elements */
[data-streamdown="strong"] { }
[data-streamdown="link"] { }
[data-streamdown="inline-code"] { }

/* Lists */
[data-streamdown="ordered-list"] { }
[data-streamdown="unordered-list"] { }
[data-streamdown="list-item"] { }

/* Blocks */
[data-streamdown="blockquote"] { }
[data-streamdown="horizontal-rule"] { }

/* Code */
[data-streamdown="code-block"] { }
[data-streamdown="mermaid-block"] { }

/* Tables */
[data-streamdown="table-wrapper"] { }
[data-streamdown="table"] { }
[data-streamdown="table-header"] { }
[data-streamdown="table-body"] { }
[data-streamdown="table-row"] { }
[data-streamdown="table-header-cell"] { }
[data-streamdown="table-cell"] { }

/* Other */
[data-streamdown="superscript"] { }
[data-streamdown="subscript"] { }
```

### Example Usage

Here's a practical example of customizing Streamdown styles with CSS:

```css title="styles/streamdown.css"
/* Custom heading styles */
[data-streamdown="heading-1"] {
  color: #1a202c;
  border-bottom: 2px solid #e2e8f0;
  padding-bottom: 0.5rem;
}

[data-streamdown="heading-2"] {
  color: #2d3748;
  margin-top: 2rem;
}

/* Custom link appearance */
[data-streamdown="link"] {
  color: #3182ce;
  text-decoration: none;
  border-bottom: 1px solid #90cdf4;
  transition: border-color 0.2s;
}

[data-streamdown="link"]:hover {
  border-bottom-color: #3182ce;
}

/* Custom code block styling */
[data-streamdown="code-block"] {
  border-radius: 0.5rem;
  border: 1px solid #e2e8f0;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

/* Custom table styling */
[data-streamdown="table"] {
  border-radius: 0.5rem;
  overflow: hidden;
}

[data-streamdown="table-header"] {
  background: linear-gradient(to bottom, #f7fafc, #edf2f7);
}

/* Custom blockquote styling */
[data-streamdown="blockquote"] {
  background-color: #f7fafc;
  border-left-color: #4299e1;
  border-radius: 0.25rem;
}
```

### Scoped Styling

You can scope your styles to specific instances of Streamdown by using the `className` prop:

```tsx title="app/page.tsx"
<Streamdown className="docs-content">
  {markdown}
</Streamdown>
```

```css title="styles/streamdown.css"
/* Styles only apply to this specific instance */
.docs-content [data-streamdown="heading-1"] {
  font-family: 'Inter', sans-serif;
  letter-spacing: -0.02em;
}

.docs-content [data-streamdown="code-block"] {
  font-family: 'Fira Code', monospace;
}
```

## Combining Approaches

For maximum flexibility, you can combine both approaches - using custom components for structural changes and CSS for visual styling:

```tsx title="app/page.tsx"
<Streamdown
  className="custom-markdown"
  components={{
    h1: ({ children, ...props }) => (
      <h1 {...props}>
        <span className="heading-icon">📖</span>
        {children}
      </h1>
    ),
  }}
>
  {markdown}
</Streamdown>
```

```css title="styles/streamdown.css"
.custom-markdown [data-streamdown="heading-1"] {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.custom-markdown .heading-icon {
  font-size: 1.5rem;
}
```

## Additional Styling Props

Beyond component overrides and CSS, Streamdown provides additional styling-related props:

### Container Class Name

Use the `className` prop to add custom classes to the Streamdown container:

```tsx title="app/page.tsx"
<Streamdown className="prose prose-lg dark:prose-invert max-w-none">
  {markdown}
</Streamdown>
```

### Syntax Highlighting Themes

Customize code block appearance with Shiki themes:

```tsx title="app/page.tsx"
<Streamdown
  shikiTheme={['github-light', 'github-dark']}
>
  {markdown}
</Streamdown>
```

See the [Code Blocks](/docs/code-blocks) documentation for more details on syntax highlighting customization.

## Best Practices

When customizing Streamdown styles, consider these best practices:

1. **Start with CSS Variables** - For most theming needs (colors, borders, radius), modifying CSS variables in `globals.css` is the simplest and most maintainable approach.

2. **Use `data-streamdown` Selectors for Specific Elements** - When you need to target individual elements without affecting the entire theme, use the `data-streamdown` attribute selectors.

3. **Use Custom Components for Structural Changes** - When you need to change the HTML structure or add wrapper elements, use the `components` prop.

4. **Maintain Accessibility** - Ensure your custom styles maintain proper color contrast, focus states, and semantic HTML structure.

5. **Test During Streaming** - Verify that your custom styles work well with incomplete content during streaming.

6. **Scope Your Styles** - Use the `className` prop to scope styles and avoid conflicts with other parts of your application.

7. **Preserve Animations** - Streamdown includes built-in animations for smooth streaming. Be careful not to override animation-related classes unless intentional.

## Styling Priority

The three styling approaches have the following priority (highest to lowest):

1. **Custom Components** - Complete control over rendering
2. **CSS via `data-streamdown` selectors** - Element-specific styling
3. **CSS Variables** - Global theme tokens
